import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import IResponse from '@/services/response.service';
import axios, { RawAxiosRequestHeaders } from 'axios';
import { defer, of, catchError, map, concatMap, forkJoin, Observable, retry, tap, lastValueFrom } from 'rxjs';
import DyHelper, { DyHelperRequest } from '@/modules/dy/dy.helper';
import * as crypto from 'crypto';
import IHelper from '@/services/helper.service';
import { IWonewSer } from '@/typing';
import { PubTaskEntity } from '@/db/entitys/pub-task.entity';
import { AccountEntity } from '@/db/entitys/account.entity';
import { VideoEntity } from '@/db/entitys/video.entity';
import { DyBindService } from './dy.bind.service';
import * as fs from "fs-extra"
import * as path from "path"
import ILogger from '@/services/logger.service';
import * as https from "https"
import * as shelljs from "shelljs"
import { SyncEmailService } from '../sync-email/sync-email.service';
import * as puppeteer from "puppeteer"
import IConstants from '@/core/constants';
import * as moment from "moment"


@Injectable()
export class DyService {
  constructor(
    private readonly dyBindService: DyBindService,
    private readonly syncEmailService: SyncEmailService,
  ) {}
  publishVideoToAccount(taskSchema: PubTaskEntity, accountSchema: AccountEntity, videoSchema: VideoEntity): Observable<IWonewSer.PublishTaskResult> {
    return defer(() => this.publishVideoToAccountByPuppeteer(taskSchema, accountSchema, videoSchema)) 
  }
  async publishVideoToAccountByPuppeteer(taskSchema: PubTaskEntity, accountSchema: AccountEntity, videoSchema: VideoEntity): Promise<IWonewSer.PublishTaskResult> {
    let browser: puppeteer.Browser | undefined = undefined
    let res: IWonewSer.PublishTaskResult = {status: false, message: "未知错误", resp: null}
    try {
      browser = await puppeteer.launch({
        headless: false,
        defaultViewport: {width: 1280, height: 900},
        args: ['--no-sandbox','--disable-setuid-sandbox', "--window-size=1280,900", "--disable-notifications", ],
      })
      const browserContext = browser.defaultBrowserContext();
      browserContext.overridePermissions('https://creator.douyin.com', ['geolocation']);
      const page = await browserContext.newPage()
      const cookies = JSON.parse(accountSchema.cookie) as puppeteer.Cookie[]
      for(let i = 0; i < cookies.length; i++){
        await page.setCookie(cookies[i])
      }
      // await page.goto("https://www.douyin.com")
      // await page.waitForResponse(response => response.url().includes("https://www.douyin.com/aweme/v1/web/query/user"))
      // await IHelper.sleep(2000)
      const titleConfig = this.buildPubTitleConfig({taskSchema} as IWonewSer.DyPublishTask, false)
      await page.setRequestInterception(true)
      page.on('request', (req: puppeteer.HTTPRequest) => {
        if (req.url().includes("https://creator.douyin.com/web/api/media/aweme/create")) {
          const psd = {}
          req.postData().split("&").forEach(item => {
            const [k, v] = item.split("=")
            psd[k] = decodeURIComponent(v)
          })
          Object.assign(psd, titleConfig)
          req.continue({postData: new URLSearchParams(psd).toString()})
        } else {
          req.continue();
        }
        
      });
      await page.goto("https://creator.douyin.com/creator-micro/content/upload")
      await page.evaluate(() => {
        localStorage.setItem("creator_pc_master_guide_guide-data-center", "true")
      })
      const videoPath = path.join(IConstants.publicDir, `uploads/temp/${taskSchema.title}.mp4`)
      fs.copyFileSync(IHelper.getAssetAbsPathByStaticPath(videoSchema.video), videoPath)
      const inputEle = await page.waitForSelector("input[name='upload-btn']")
      await inputEle.uploadFile(videoPath)
      await page.waitForSelector('[class^="long-card-"]')
      await page.waitForSelector('[class^="recommendCover-"] img')
      await page.waitForSelector('[class^="recommendCover-"]').then(el => el.click())
      const titleInputEle = await page.waitForSelector('input.semi-input')
      await titleInputEle.type(taskSchema.title)
      await IHelper.sleep(5000)
      const submitBtnEle = await page.waitForSelector('[class^=content-confirm-container-] button')
      await submitBtnEle.click()
      const response = await page.waitForResponse(response => {
        return response.url().includes("https://creator.douyin.com/web/api/media/aweme/create")
      })
      const result = await response.json()
      if (!result?.aweme?.aweme_id) {
        throw new Error("发布错误")
      }
      ILogger.info(`发布[${videoSchema.name}]到账号[${accountSchema.name}]: ${JSON.stringify(result)}`)
      res = {status: true, message: "success", resp: result}
    } catch(error) {
      res.message = error.message || "未知错误"
    }
    if (browser) {
      browser.close().catch(e => e)
    }
    return res
  }
  publishVideoToAccount1(taskSchema: PubTaskEntity, accountSchema: AccountEntity, videoSchema: VideoEntity): Observable<IWonewSer.PublishTaskResult> {
    const task: IWonewSer.DyPublishTask = {
      uuid: `发布[${videoSchema.name}]到账号[${accountSchema.name}]`,
      startAt: Date.now(),
      taskSchema, accountSchema, videoSchema,
      videoBuffer: fs.readFileSync(IHelper.getAssetAbsPathByStaticPath(videoSchema.video)),
      coverBuffer: fs.readFileSync(IHelper.getAssetAbsPathByStaticPath(videoSchema.cover)),
      res_uploadCover: {},
      res_uploadVideo: {},
    }

    // @ts-ignore
    return of(null).pipe(
      // tap(() => ILogger.info(`${task.uuid}: 开始检查 cookie`)),
      concatMap(() => 
        this.dyBindService.checkCookie(accountSchema.cookie).pipe(
          map(res => {
            if (!res.valid) {
              ILogger.info(`Account cookie expired. ${JSON.stringify({})}`)
              throw new HttpException("Account cookie expired.", HttpStatus.BAD_REQUEST)
            }
            if (!res.platformUser) {
              ILogger.info(`Get platform user failed. ${JSON.stringify({})}`)
              throw new HttpException("Get platform user failed.", HttpStatus.BAD_REQUEST)
            }
            task.platformUser = res.platformUser
            return task
          })
        )
      ),
      tap(() => ILogger.info(`${task.uuid}: 开始 requestAuth`)),
      concatMap(() => this.uploadVideo_requestAuth(task)),
      tap(() => ILogger.info(`${task.uuid}: 开始 applyUploadInner`)),
      concatMap(() => this.uploadVideo_applyUploadInner(task)),
      tap(() => ILogger.info(`${task.uuid}: 开始 uploadFullVideo`)),
      concatMap(() => this.uploadVideo_uploadFullVideo(task)),
      tap(() => ILogger.info(`${task.uuid}: 开始 commitUploadInner`)),
      concatMap(() => this.uploadVideo_commitUploadInner(task)),
      tap(() => ILogger.info(`${task.uuid}: 开始 uploadCover`)),
      concatMap(() => this.uploadCover(task)),
      tap(() => ILogger.info(`${task.uuid}: 开始 publishTask`)),
      concatMap(() => this.publishTask(task)),
      tap(() => ILogger.info(`${task.uuid}: publishTask 完成`)),
      map(() => {
        const { videoBuffer, coverBuffer, ...rest } = task;
        return {status: true, message: "success", resp: rest}
      }),
      catchError(error => {
        const { videoBuffer, coverBuffer, ...rest } = task;
        return of({status: false, message: error.message, resp: rest})
      })
    );
  }
  publish(opt: { videoFile: Express.Multer.File, coverFile: Express.Multer.File, config: any }) {
    
  }

  uploadVideo_requestAuth(task: IWonewSer.DyPublishTask) {
    const uri: string = `https://creator.douyin.com/web/api/media/upload/auth/v5/`;
    const params = {
      // "cookie_enabled": "true",
      // "screen_width": "1920",
      // "screen_height": "1080",
      // "browser_language": "zh-CN",
      // "browser_platform": "MacIntel",
      // "browser_name": "Mozilla",
      // "browser_version": "5.0+(Macintosh;+Intel+Mac+OS+X+10_15_7)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/120.0.0.0+Safari/537.36",
      // "browser_online": "true",
      'timezone_name': 'Asia/Shanghai',
      // "aid": "1128",
      // "msToken": "R_OQjLCGLoSo-xshlS4o-Rk-VeWFuk2avD9yITqKXCdjqtyyTySbtd-Gde7AaZN3a7BopTLsIYyd3O4_byW5LY893P4bmv_FUgzaYjVUjvMt24j9z6oJhA",
      // "a_bogus": "QvBmhO20Msm13D3eahkz9CXmFPg0YW4hgZEPHtIL8zwo",
      // "X-Bogus": "DFSzsdVuzEUANSvEti/BOORXoR0n",
      // "_signature": "_02B4Z6wo00001PUiGYAAAIDBGwfdf0wiKZD1Jh0AAFj13dDx8hkj1cBWUbFE4qcD1Nuq-HcMA8A4jFz9O-HA2HJmyFtMrbsAvTAc2ZL-AAfKu9Og6bdYLgcxaJ9wgFZaTWE87HPJU3znYphh81"
    };
    const headers: RawAxiosRequestHeaders = {
      'Host': 'creator.douyin.com',
      'Cookie': IHelper.covert2StandardCookieStr(task.accountSchema.cookie),
      'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
      'accept': 'application/json, text/plain, */*',
      // 'x-secsdk-csrf-token': '000100000001659f236613984139ebcfbd538a9b9eb67315152b7bd57dd6a644166a279dab2e17ab0611f11eeca8',
      'sec-ch-ua-mobile': '?0',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      'sec-ch-ua-platform': '"macOS"',
      'sec-fetch-site': 'same-origin',
      'sec-fetch-mode': 'cors',
      'sec-fetch-dest': 'empty',
      'referer': 'https://creator.douyin.com/creator-micro/content/publish?enter_from=publish_page',
      'accept-language': 'zh-CN,zh;q=0.9',
    };
    return defer(() =>
      axios.get(uri, { params, headers }),
    ).pipe(
      map(res => {
        // {
        //   "ak": "AKLTYjdjYTUwZWQwZDU0NDRmMmEwNWU5NmE1MTdiYzUyZTg",
        //   "auth": "{\"AccessKeyID\":\"AKTPZTU5YzZjNDUwMGYyNDcwMzkzYTI4ZWNmMGY3OTU5OTM\",\"SecretAccessKey\":\"fBTCJScp1TsFInu6e1veijHbwWZvgnyx2TXVreBJU8Hi6ETsdxGKjjVsXDf5RVKU\",\"SessionToken\":\"STS2eyJMVEFjY2Vzc0tleUlEIjoiQUtMVFlqZGpZVFV3WldRd1pEVTBORFJtTW1Fd05XVTVObUUxTVRkaVl6VXlaVGciLCJBY2Nlc3NLZXlJRCI6IkFLVFBaVFU1WXpaak5EVXdNR1l5TkRjd016a3pZVEk0WldObU1HWTNPVFU1T1RNIiwiU2lnbmVkU2VjcmV0QWNjZXNzS2V5IjoiL2UzYm1tRUtrL2RxMU02N3ExQnU1SENxWWJoV044NWNGNWk0ajBPVG9LYU1nSHlJdWhWbllTazVvdkY1TnpTRjhXQWs5ektGUEtFeWRpdnAvNjVOcHphcWlTby92TUowSEtNMHJPTm9pSkU9IiwiRXhwaXJlZFRpbWUiOjE3MDU2NTU2MjMsIlBvbGljeVN0cmluZyI6IntcIlN0YXRlbWVudFwiOlt7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJ2b2Q6KlwiLFwiSW1hZ2VYOipcIl0sXCJSZXNvdXJjZVwiOltcIipcIl19LHtcIkVmZmVjdFwiOlwiQWxsb3dcIixcIkFjdGlvblwiOltcIlVzZXJJZFwiXSxcIlJlc291cmNlXCI6W1wiNTcyMjE5OTQ5NTkxNjYxXCJdfSx7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJBcHBJZFwiXSxcIlJlc291cmNlXCI6W1wiMFwiXX0se1wiRWZmZWN0XCI6XCJBbGxvd1wiLFwiQWN0aW9uXCI6W1wiVXNlclJlZmVyZW5jZVwiXSxcIlJlc291cmNlXCI6W1wie1xcXCJwc21cXFwiOlxcXCJkb3V5aW4uY3JlYXRvci5jb250ZW50XFxcIn1cIl19LHtcIkVmZmVjdFwiOlwiQWxsb3dcIixcIkFjdGlvblwiOltcIlNlc3Npb25DaGVja1wiXSxcIlJlc291cmNlXCI6W1wiVWlkXCJdfSx7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJQU01cIl0sXCJSZXNvdXJjZVwiOltcImRvdXlpbi5jcmVhdG9yLmNvbnRlbnRcIl19XX0iLCJTaWduYXR1cmUiOiIwNWE1YzI1NmZlMDA4YjVkNjkyOThlOWMxZjkwMTRlZjE2YWU3YmI3OTAzMjdmZjllZTg5ZjNlZWI5NGZhMTdlIn0=\",\"ExpiredTime\":\"2024-01-19T17:13:43+08:00\",\"CurrentTime\":\"2024-01-17T17:13:43+08:00\"}",
        //   "extra": {
        //   "logid": "2024011717134329C33002D16B5D01F1C7",
        //     "now": 1705482823000
        // },
        //   "status_code": 0
        // }
        if (res.data?.status_code !== 0) {
          ILogger.info(`Get upload auth failed. ${JSON.stringify(res.data)}`)
          throw new HttpException(`Get upload auth failed.`, HttpStatus.BAD_REQUEST);
        }
        task.res_requestAuth = res.data;
        return task;
      }),
    );
  }

  uploadVideo_applyUploadInner(task: IWonewSer.DyPublishTask) {
    const uri: string = 'https://vod.bytedanceapi.com/';
    const uploadAuth = this.getTaskUploadAuth(task);
    const params = {
      'Action': 'ApplyUploadInner',
      'Version': '2020-11-19',
      'SpaceName': 'aweme',
      'FileType': 'video',
      'IsInner': '1',
      'FileSize': task.videoBuffer.length,
      'app_id': '2906',
      'user_id': this.getUid(task),
      's': Math.random().toString(36).substring(2),
    };
    const request: DyHelperRequest = {
      headers: {},
      params,
      body: undefined,
      pathname: DyHelper.getPathByURL(uri),
      region: 'cn-north-1',
      timeout: 3000,
      url: uri,
      method: 'GET',
    };
    const dyHelper = new DyHelper(request, 'vod');
    const authHeaders = dyHelper.addAuthorization({
      accessKeyId: uploadAuth.AccessKeyID,
      secretAccessKey: uploadAuth.SecretAccessKey,
      sessionToken: uploadAuth.SessionToken,
    }, new Date());

    const headers = {
      'Host': 'vod.bytedanceapi.com',
      'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
      // 'x-amz-security-token': 'STS2eyJMVEFjY2Vzc0tleUlEIjoiQUtMVFlqZGpZVFV3WldRd1pEVTBORFJtTW1Fd05XVTVObUUxTVRkaVl6VXlaVGciLCJBY2Nlc3NLZXlJRCI6IkFLVFBNekF5TWpjMll6VTNOVEUwTkRoak9UZ3haV1UwTjJVM01HVTBZMlUzTmpVIiwiU2lnbmVkU2VjcmV0QWNjZXNzS2V5IjoiU0xLU0Z2TFZZSU1XNElSQ2pFL2hlTnpCK1VkeDJXVXB2MnJNTHl6UlJZcU5uWnZ1TGtjZFZHTDF0V213NlpHQ3RCZndqQUxFMGJianM0SFJMQjVrSlZHUFp3Tm5SbU9XZm9GV1BrN0FuQ1U9IiwiRXhwaXJlZFRpbWUiOjE3MDU2MzY1NTAsIlBvbGljeVN0cmluZyI6IntcIlN0YXRlbWVudFwiOlt7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJ2b2Q6KlwiLFwiSW1hZ2VYOipcIl0sXCJSZXNvdXJjZVwiOltcIipcIl19LHtcIkVmZmVjdFwiOlwiQWxsb3dcIixcIkFjdGlvblwiOltcIlVzZXJJZFwiXSxcIlJlc291cmNlXCI6W1wiNTcyMjE5OTQ5NTkxNjYxXCJdfSx7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJBcHBJZFwiXSxcIlJlc291cmNlXCI6W1wiMTEyOFwiXX0se1wiRWZmZWN0XCI6XCJBbGxvd1wiLFwiQWN0aW9uXCI6W1wiVXNlclJlZmVyZW5jZVwiXSxcIlJlc291cmNlXCI6W1wie1xcXCJwc21cXFwiOlxcXCJkb3V5aW4uY3JlYXRvci5jb250ZW50XFxcIn1cIl19LHtcIkVmZmVjdFwiOlwiQWxsb3dcIixcIkFjdGlvblwiOltcIlNlc3Npb25DaGVja1wiXSxcIlJlc291cmNlXCI6W1wiVWlkXCJdfSx7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJQU01cIl0sXCJSZXNvdXJjZVwiOltcImRvdXlpbi5jcmVhdG9yLmNvbnRlbnRcIl19XX0iLCJTaWduYXR1cmUiOiI2ZDcxYjYzMDgyMjg4MDYxZDY5NzUwN2E0OTgyOTFhNDEyZGUyYTVmMmZhNjMzMWM1NDk5NzczYThlOTQ5ZmU4In0=',
      // 'x-amz-date': '20240117T035550Z',
      // 'authorization': 'AWS4-HMAC-SHA256 Credential=AKTPMzAyMjc2YzU3NTE0NDhjOTgxZWU0N2U3MGU0Y2U3NjU/20240117/cn-north-1/vod/aws4_request, SignedHeaders=x-amz-date;x-amz-security-token, Signature=da26c56dfc31fab79db5ba8ec37936a3dd13a22cfd7dc3e6990186edcb305c10',
      'sec-ch-ua-mobile': '?0',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      'sec-ch-ua-platform': '"macOS"',
      'accept': '*/*',
      'origin': 'https://creator.douyin.com',
      'sec-fetch-site': 'cross-site',
      'sec-fetch-mode': 'cors',
      'sec-fetch-dest': 'empty',
      'referer': 'https://creator.douyin.com/',
      'accept-language': 'zh-CN,zh;q=0.9',
      ...authHeaders,
    };
    return defer(() =>
      axios.get(uri, { params, headers }),
    ).pipe(
      map(res => {
        if (!Array.isArray(res.data?.Result?.InnerUploadAddress?.UploadNodes) || res.data?.Result?.InnerUploadAddress?.UploadNodes.length <= 0) {
          ILogger.info(`ApplyUploadInner request failed. ${JSON.stringify(res.data)}`)
          throw new HttpException(`ApplyUploadInner request failed.`, HttpStatus.BAD_REQUEST);
        }
        task.res_uploadVideo.res_uploadVideo_applyUploadInner = res.data;
        return task;
      }),
    );
  }

  getUploadId(): string {
    return crypto.randomUUID();
  }

  uploadVideo_uploadFullVideo(task: IWonewSer.DyPublishTask) {
    const prePartLength = 3145728;
    const buffer = task.videoBuffer;
    const totalPart = Math.ceil(buffer.length / prePartLength);
    const uploadId = this.getUploadId();
    const uploadNode = this.parseUploadNode(task.res_uploadVideo.res_uploadVideo_applyUploadInner);
    ILogger.info(`${task.uuid}: 分片上传 总共${totalPart}片`)
    const partList: IWonewSer.DyUploadPart[] = IHelper.getArray(totalPart).map(idx => {
      const partBuffer = buffer.subarray(idx * prePartLength, (idx + 1) * prePartLength);
      return {
        buffer: partBuffer,
        crc32: DyHelper.getBufferHash(partBuffer),
        uploadId,
        offset: (idx * prePartLength).toString(),
        idx: (idx + 1).toString(),
        node: uploadNode,
      };
    });
    return forkJoin(
      [...partList.map(part => this.uploadVideo_uploadPrePart(part, task))],
    ).pipe(
      map(d => {
        task.res_uploadVideo.res_uploadVideo_uploadFullVideo = d;
      }),
      tap(() => ILogger.info(`${task.uuid}: 分片上传 开始 merge`)),
      concatMap(() => this.uploadVideo_mergeVideo(partList, task)),
      tap(() => ILogger.info(`${task.uuid}: 分片上传 结束 merge`)),
      map(d => {
        task.res_uploadVideo.res_uploadVideo_mergeVideo = d;
        return task;
      }),
    );
  }

  uploadVideo_uploadPrePart(part: IWonewSer.DyUploadPart, task: IWonewSer.DyPublishTask) {
    const params = {
      'uploadid': part.uploadId,
      'part_number': part.idx,
      'phase': 'transfer',
      'part_offset': part.offset,
    };
    const headers: RawAxiosRequestHeaders = {
      'Host': part.node.UploadHost,
      'Pragma': 'no-cache',
      'Cache-Control': 'no-cache',
      'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
      'X-Storage-U': this.getUid(task),
      'Content-CRC32': part.crc32,
      'sec-ch-ua-mobile': '?0',
      'Authorization': part.node.Auth,
      'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      'Content-Type': 'application/octet-stream',
      'Content-Disposition': 'attachment; filename="undefined"',
      'sec-ch-ua-platform': '"macOS"',
      'Accept': '*/*',
      'Origin': 'https://creator.douyin.com',
      'Sec-Fetch-Site': 'same-site',
      'Sec-Fetch-Mode': 'cors',
      'Sec-Fetch-Dest': 'empty',
      'Referer': 'https://creator.douyin.com/',
      'Accept-Language': 'zh-CN,zh;q=0.9',
    };
    
    ILogger.info(`${task.uuid}: 分片上传 开始上传第${part.idx}片`)
    return defer(() =>
      axios.post(part.node.UploadUri, part.buffer, { params, headers }),
    ).pipe(
      map(res => {
        ILogger.info(`${task.uuid}: 分片上传 结束上传第${part.idx}片`)
        if (res.data?.code !== 2000) {
          ILogger.info(`UploadVideo_uploadPrePart res code not 2000. ${JSON.stringify(res.data)}`)
          throw new HttpException(`UploadVideo_uploadPrePart res code not 2000.`, HttpStatus.BAD_REQUEST);
        }
        if (res.data?.data?.crc32 !== part.crc32) {
          ILogger.info(`UploadVideo_uploadPrePart res code not 2000. ${JSON.stringify(res.data)}`)
          throw new HttpException(`UploadVideo_uploadPrePart res crc32 not match.`, HttpStatus.BAD_REQUEST);
        }
        return res.data;
      }),
    );
  }

  uploadVideo_mergeVideo(partList: IWonewSer.DyUploadPart[], task: IWonewSer.DyPublishTask) {
    const uri: string = partList[0].node.UploadUri;
    const data: string = partList.map(part => `${part.idx}:${part.crc32}`).join(',');
    const params = {
      'uploadmode': 'part',
      'phase': 'finish',
      'uploadid': partList[0].uploadId,
    };
    const headers: RawAxiosRequestHeaders = {
      'Host': partList[0].node.UploadHost,
      'Pragma': 'no-cache',
      'Cache-Control': 'no-cache',
      'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
      'Content-Type': 'text/plain;charset=UTF-8',
      'X-Storage-U': this.getUid(task),
      'sec-ch-ua-mobile': '?0',
      'Authorization': partList[0].node.Auth,
      'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      'sec-ch-ua-platform': '"macOS"',
      'Accept': '*/*',
      'Origin': 'https://creator.douyin.com',
      'Sec-Fetch-Site': 'cross-site',
      'Sec-Fetch-Mode': 'cors',
      'Sec-Fetch-Dest': 'empty',
      'Referer': 'https://creator.douyin.com/',
      'Accept-Language': 'zh-CN,zh;q=0.9',
    };
    return defer(() =>
      axios.post(uri, data, { params, headers }),
    ).pipe(
      map(res => res.data),
    );
  }

  uploadVideo_commitUploadInner(task: IWonewSer.DyPublishTask) {
    const uri: string = `https://vod.bytedanceapi.com/`;
    const uploadAuth = this.getTaskUploadAuth(task);
    let uploadNode = this.parseUploadNode(task.res_uploadVideo.res_uploadVideo_applyUploadInner);
    const data = {
      'SessionKey': uploadNode.SessionKey,
      'Functions': [{ 'name': 'GetMeta' }, { 'name': 'Snapshot', 'input': { 'SnapshotTime': 0 } }],
    };
    const params = {
      'Action': 'CommitUploadInner',
      'Version': '2020-11-19',
      'SpaceName': 'aweme',
      'app_id': '2906',
      'user_id': this.getUid(task),
    };
    const request: DyHelperRequest = {
      headers: {},
      params,
      body: { ...data },
      pathname: DyHelper.getPathByURL(uri),
      region: 'cn-north-1',
      timeout: 3000,
      url: uri,
      method: 'POST',
    };
    const dyHelper = new DyHelper(request, 'vod');
    const authHeaders = dyHelper.addAuthorization({
      accessKeyId: uploadAuth.AccessKeyID,
      secretAccessKey: uploadAuth.SecretAccessKey,
      sessionToken: uploadAuth.SessionToken,
    }, new Date());
    const headers: RawAxiosRequestHeaders = {
      'Host': 'vod.bytedanceapi.com',
      'pragma': 'no-cache',
      'cache-control': 'no-cache',
      'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
      'sec-ch-ua-mobile': '?0',
      // 'x-amz-content-sha256': 'e2899101736914fcbd5c1db446fb1bc6e2fb0f8650d115efc304282fd799478c',
      // 'x-amz-security-token': 'STS2eyJMVEFjY2Vzc0tleUlEIjoiQUtMVFlqZGpZVFV3WldRd1pEVTBORFJtTW1Fd05XVTVObUUxTVRkaVl6VXlaVGciLCJBY2Nlc3NLZXlJRCI6IkFLVFBPVFEzTldFNU16Z3hNREZtTkdNMVptRmpOR1psTkRrNU1UWmhNemMxTVRNIiwiU2lnbmVkU2VjcmV0QWNjZXNzS2V5IjoiVURMVzRCeWlCb2hGL1I5NWhwMkpHeWF1cFREM1NFNk9EbkJ3cEZZMytRR082VmoveDFnQlk2dGFHcEFwZm9QRno0N241amFXUCtWd0hWOW1jRDZCaFplNVBBSStEQlVZZ2F4NXZPTVZyUms9IiwiRXhwaXJlZFRpbWUiOjE3MDU3MTcwODMsIlBvbGljeVN0cmluZyI6IntcIlN0YXRlbWVudFwiOlt7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJ2b2Q6KlwiLFwiSW1hZ2VYOipcIl0sXCJSZXNvdXJjZVwiOltcIipcIl19LHtcIkVmZmVjdFwiOlwiQWxsb3dcIixcIkFjdGlvblwiOltcIlVzZXJJZFwiXSxcIlJlc291cmNlXCI6W1wiNTcyMjE5OTQ5NTkxNjYxXCJdfSx7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJBcHBJZFwiXSxcIlJlc291cmNlXCI6W1wiMTEyOFwiXX0se1wiRWZmZWN0XCI6XCJBbGxvd1wiLFwiQWN0aW9uXCI6W1wiVXNlclJlZmVyZW5jZVwiXSxcIlJlc291cmNlXCI6W1wie1xcXCJwc21cXFwiOlxcXCJkb3V5aW4uY3JlYXRvci5jb250ZW50XFxcIn1cIl19LHtcIkVmZmVjdFwiOlwiQWxsb3dcIixcIkFjdGlvblwiOltcIlNlc3Npb25DaGVja1wiXSxcIlJlc291cmNlXCI6W1wiVWlkXCJdfSx7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJQU01cIl0sXCJSZXNvdXJjZVwiOltcImRvdXlpbi5jcmVhdG9yLmNvbnRlbnRcIl19XX0iLCJTaWduYXR1cmUiOiJlN2VjZjY0ZWQ1MmMwYTdjOGY3OTI0OGE0ZjYwNWZmNmIyNTRiNGYxZGM1NjY2NWRmNWY3ZTg0ZDEyZjg4OTkwIn0=',
      // 'x-amz-date': '20240118T021806Z',
      // 'authorization': 'AWS4-HMAC-SHA256 Credential=AKTPOTQ3NWE5MzgxMDFmNGM1ZmFjNGZlNDk5MTZhMzc1MTM/20240118/cn-north-1/vod/aws4_request, SignedHeaders=x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=86b40ce6add68a456a5af11e396111eea16a1cb277025eacc27f86f6e9cd8436',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      'content-type': 'text/plain;charset=UTF-8',
      'sec-ch-ua-platform': '"macOS"',
      'accept': '*/*',
      'origin': 'https://creator.douyin.com',
      'sec-fetch-site': 'cross-site',
      'sec-fetch-mode': 'cors',
      'sec-fetch-dest': 'empty',
      'referer': 'https://creator.douyin.com/',
      'accept-language': 'zh-CN,zh;q=0.9',
      ...authHeaders,
    };
    return defer(() =>
      axios.post(uri, JSON.stringify(data), { params, headers }),
    ).pipe(
      map(res => {
        task.res_uploadVideo.res_uploadVideo_commitUploadInner = res.data;
        return task;
      }),
    );
  }

  uploadCover(task: IWonewSer.DyPublishTask) {
    return of(null).pipe(
      tap(() => ILogger.info("uploadVideo_requestAuth")),
      concatMap(() => this.uploadVideo_requestAuth(task)),
      tap(() => ILogger.info("uploadCover_applyImageUpload")),
      concatMap(() => this.uploadCover_applyImageUpload(task)),
      tap(() => ILogger.info("uploadCover_upload")),
      concatMap(() => this.uploadCover_upload(task)),
      tap(() => ILogger.info("uploadCover_commitImageUpload")),
      concatMap(() => this.uploadCover_commitImageUpload(task)),
      retry(6),
    );
  }

  uploadCover_applyImageUpload(task: IWonewSer.DyPublishTask): Observable<IWonewSer.DyPublishTask> {
    const uri: string = `https://imagex.bytedanceapi.com/`;
    const uploadAuth = this.getTaskUploadAuth(task);
    const params = {
      'Action': 'ApplyImageUpload',
      'Version': '2018-08-01',
      'ServiceId': 'jm8ajry58r',
      'app_id': '2906',
      'user_id': this.getUid(task),
      's': Math.random().toString(36).substring(2),
    };
    const request: DyHelperRequest = {
      headers: {},
      params,
      body: undefined,
      pathname: DyHelper.getPathByURL(uri),
      region: 'cn-north-1',
      timeout: 3000,
      url: uri,
      method: 'GET',
    };
    const dyHelper = new DyHelper(request, 'imagex');
    const authHeaders = dyHelper.addAuthorization({
      accessKeyId: uploadAuth.AccessKeyID,
      secretAccessKey: uploadAuth.SecretAccessKey,
      sessionToken: uploadAuth.SessionToken,
    }, new Date());
    const headers = {
      'Host': 'imagex.bytedanceapi.com',
      'pragma': 'no-cache',
      'cache-control': 'no-cache',
      'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
      'sec-ch-ua-mobile': '?0',
      // 'x-amz-security-token': 'STS2eyJMVEFjY2Vzc0tleUlEIjoiQUtMVFlqZGpZVFV3WldRd1pEVTBORFJtTW1Fd05XVTVObUUxTVRkaVl6VXlaVGciLCJBY2Nlc3NLZXlJRCI6IkFLVFBORGs0T1dVM05EVXhPRFV3TkdWbFptRmxPR0pqWmpZeE1tSTBaVEF5WTJNIiwiU2lnbmVkU2VjcmV0QWNjZXNzS2V5IjoidXEwakdyMGFSREh5Rk5YSHFweDRLcFBFT3ZxemwxRFNZa1FPMUZCTWFIM1FJMVZadVI1NW9VeDgrL0EyeFordmdqZkgzbXRIWFlnWFh0RUloMjVhR3FtOG10UEo4WkJPVW5nYVdpclVEblU9IiwiRXhwaXJlZFRpbWUiOjE3MDU3NDMwOTgsIlBvbGljeVN0cmluZyI6IntcIlN0YXRlbWVudFwiOlt7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJ2b2Q6KlwiLFwiSW1hZ2VYOipcIl0sXCJSZXNvdXJjZVwiOltcIipcIl19LHtcIkVmZmVjdFwiOlwiQWxsb3dcIixcIkFjdGlvblwiOltcIlVzZXJJZFwiXSxcIlJlc291cmNlXCI6W1wiNTcyMjE5OTQ5NTkxNjYxXCJdfSx7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJBcHBJZFwiXSxcIlJlc291cmNlXCI6W1wiMTEyOFwiXX0se1wiRWZmZWN0XCI6XCJBbGxvd1wiLFwiQWN0aW9uXCI6W1wiVXNlclJlZmVyZW5jZVwiXSxcIlJlc291cmNlXCI6W1wie1xcXCJwc21cXFwiOlxcXCJkb3V5aW4uY3JlYXRvci5jb250ZW50XFxcIn1cIl19LHtcIkVmZmVjdFwiOlwiQWxsb3dcIixcIkFjdGlvblwiOltcIlNlc3Npb25DaGVja1wiXSxcIlJlc291cmNlXCI6W1wiVWlkXCJdfSx7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJQU01cIl0sXCJSZXNvdXJjZVwiOltcImRvdXlpbi5jcmVhdG9yLmNvbnRlbnRcIl19XX0iLCJTaWduYXR1cmUiOiI3ZDdlODI4ZTUzYWI4YzEzNTcxNTdkODAyNDNhOTFlZmNkMjZiODI0ODIxM2NlZmY1YmRhZTgwNTQ4ZTJkZTBkIn0=',
      // 'x-amz-date': '20240118T093138Z',
      // 'authorization': 'AWS4-HMAC-SHA256 Credential=AKTPNDk4OWU3NDUxODUwNGVlZmFlOGJjZjYxMmI0ZTAyY2M/20240118/cn-north-1/imagex/aws4_request, SignedHeaders=x-amz-date;x-amz-security-token, Signature=b0c5379a0f3a7f33c700e35939458b7488d0e8fe6e91d60eb4f9273663af2793',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      'sec-ch-ua-platform': '"macOS"',
      'accept': '*/*',
      'origin': 'https://creator.douyin.com',
      'sec-fetch-site': 'cross-site',
      'sec-fetch-mode': 'cors',
      'sec-fetch-dest': 'empty',
      'referer': 'https://creator.douyin.com/',
      'accept-language': 'zh-CN,zh;q=0.9',
      ...authHeaders,
    };
    return defer(() =>
      axios.get('https://imagex.bytedanceapi.com/', { params, headers, }),
    ).pipe(
      map(res => {
        if (!Array.isArray(res.data?.Result?.InnerUploadAddress?.UploadNodes) || res.data?.Result?.InnerUploadAddress?.UploadNodes.length <= 0) {
          ILogger.info(`UploadCover_applyImageUpload failed. ${JSON.stringify(res.data)}`)
          throw new HttpException(`UploadCover_applyImageUpload failed.`, HttpStatus.BAD_REQUEST);
        }
        if (!task.res_uploadCover) {
          // @ts-ignore
          task.res_uploadCover = {};
        }
        task.res_uploadCover.res_uploadCover_applyImageUpload = res.data;
        return task;
      }),
    );
  }

  uploadCover_upload(task: IWonewSer.DyPublishTask) {
    const uploadNode = this.parseUploadNode(task.res_uploadCover.res_uploadCover_applyImageUpload);
    const crc32: string = DyHelper.getBufferHash(task.coverBuffer);
    const headers: RawAxiosRequestHeaders = {
      'X-Storage-U': this.getUid(task),
      'Content-CRC32': crc32,
      'Authorization': uploadNode.Auth,
    };
    const buffer = new Uint8Array(task.coverBuffer).buffer;

    return defer(() =>
      axios.post(uploadNode.UploadUri, buffer, {headers}),
    ).pipe(
      map(res => {
        if (res.data?.data?.crc32 !== crc32) {
          ILogger.info(`UploadCover_upload failed. ${JSON.stringify(res.data)}`)
          throw new HttpException(`UploadCover_upload failed.`, HttpStatus.BAD_REQUEST);
        }
        task.res_uploadCover.res_uploadCover_upload = res.data;
        return task;
      }),
    );
  }

  //https://github.com/axios/axios/issues/5636

  uploadCover_commitImageUpload(task: IWonewSer.DyPublishTask) {
    const uri: string = 'https://imagex.bytedanceapi.com/';
    const uploadNode = this.parseUploadNode(task.res_uploadCover.res_uploadCover_applyImageUpload);
    const uploadAuth = this.getTaskUploadAuth(task);
    const data: any = {
      'SessionKey': uploadNode.SessionKey,
    };
    const params = {
      'Action': 'CommitImageUpload',
      'Version': '2018-08-01',
      'ServiceId': 'jm8ajry58r',
      'app_id': '2906',
      'user_id': this.getUid(task),
    };
    const request: DyHelperRequest = {
      headers: {},
      params,
      body: { ...data },
      pathname: DyHelper.getPathByURL(uri),
      region: 'cn-north-1',
      timeout: 3000,
      url: uri,
      method: 'POST',
    };
    const dyHelper: DyHelper = new DyHelper(request, 'imagex');
    const authHeaders: RawAxiosRequestHeaders = dyHelper.addAuthorization(
      {
        accessKeyId: uploadAuth.AccessKeyID,
        secretAccessKey: uploadAuth.SecretAccessKey,
        sessionToken: uploadAuth.SessionToken,
      },
      new Date(),
    );
    const headers = {
      'Host': 'imagex.bytedanceapi.com',
      'pragma': 'no-cache',
      'cache-control': 'no-cache',
      'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
      'sec-ch-ua-mobile': '?0',
      // 'authorization': 'AWS4-HMAC-SHA256 Credential=AKTPNDk4OWU3NDUxODUwNGVlZmFlOGJjZjYxMmI0ZTAyY2M/20240118/cn-north-1/imagex/aws4_request, SignedHeaders=x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=25ee481254bd4ca6d91dc07b93988e20059bd8992b147f392422a78d00e6802f',
      // 'x-amz-content-sha256': 'ac70aee180d912f5cee047150b1725aad3c2b623fceda800a721adcbaf93f2e8',
      // 'x-amz-security-token': 'STS2eyJMVEFjY2Vzc0tleUlEIjoiQUtMVFlqZGpZVFV3WldRd1pEVTBORFJtTW1Fd05XVTVObUUxTVRkaVl6VXlaVGciLCJBY2Nlc3NLZXlJRCI6IkFLVFBORGs0T1dVM05EVXhPRFV3TkdWbFptRmxPR0pqWmpZeE1tSTBaVEF5WTJNIiwiU2lnbmVkU2VjcmV0QWNjZXNzS2V5IjoidXEwakdyMGFSREh5Rk5YSHFweDRLcFBFT3ZxemwxRFNZa1FPMUZCTWFIM1FJMVZadVI1NW9VeDgrL0EyeFordmdqZkgzbXRIWFlnWFh0RUloMjVhR3FtOG10UEo4WkJPVW5nYVdpclVEblU9IiwiRXhwaXJlZFRpbWUiOjE3MDU3NDMwOTgsIlBvbGljeVN0cmluZyI6IntcIlN0YXRlbWVudFwiOlt7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJ2b2Q6KlwiLFwiSW1hZ2VYOipcIl0sXCJSZXNvdXJjZVwiOltcIipcIl19LHtcIkVmZmVjdFwiOlwiQWxsb3dcIixcIkFjdGlvblwiOltcIlVzZXJJZFwiXSxcIlJlc291cmNlXCI6W1wiNTcyMjE5OTQ5NTkxNjYxXCJdfSx7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJBcHBJZFwiXSxcIlJlc291cmNlXCI6W1wiMTEyOFwiXX0se1wiRWZmZWN0XCI6XCJBbGxvd1wiLFwiQWN0aW9uXCI6W1wiVXNlclJlZmVyZW5jZVwiXSxcIlJlc291cmNlXCI6W1wie1xcXCJwc21cXFwiOlxcXCJkb3V5aW4uY3JlYXRvci5jb250ZW50XFxcIn1cIl19LHtcIkVmZmVjdFwiOlwiQWxsb3dcIixcIkFjdGlvblwiOltcIlNlc3Npb25DaGVja1wiXSxcIlJlc291cmNlXCI6W1wiVWlkXCJdfSx7XCJFZmZlY3RcIjpcIkFsbG93XCIsXCJBY3Rpb25cIjpbXCJQU01cIl0sXCJSZXNvdXJjZVwiOltcImRvdXlpbi5jcmVhdG9yLmNvbnRlbnRcIl19XX0iLCJTaWduYXR1cmUiOiI3ZDdlODI4ZTUzYWI4YzEzNTcxNTdkODAyNDNhOTFlZmNkMjZiODI0ODIxM2NlZmY1YmRhZTgwNTQ4ZTJkZTBkIn0=',
      // 'x-amz-date': '20240118T093139Z',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      'content-type': 'application/json',
      'sec-ch-ua-platform': '"macOS"',
      'accept': '*/*',
      'origin': 'https://creator.douyin.com',
      'sec-fetch-site': 'cross-site',
      'sec-fetch-mode': 'cors',
      'sec-fetch-dest': 'empty',
      'referer': 'https://creator.douyin.com/',
      'accept-language': 'zh-CN,zh;q=0.9',
      ...authHeaders,
    };
    return defer(() =>
      axios.post(uri, data, { params, headers }),
    ).pipe(
      map(res => {
        if (!Array.isArray(res.data?.Result?.Results) || res.data?.Result?.Results.length <= 0) {
          ILogger.info(`UploadCover_commitImageUpload failed. ${JSON.stringify(res.data)}`)
          throw new HttpException(`UploadCover_commitImageUpload failed.`, HttpStatus.BAD_REQUEST);
        }
        task.res_uploadCover.res_uploadCover_commitImageUpload = res.data;
        return task;
      }),
    );
  }

  buildPubTitleConfig(task: IWonewSer.DyPublishTask, encode?: boolean) {
    const title: string = task.taskSchema.title;
    const tagList: {name: string, viewCount: string, id: string, grounId: string}[] = task.taskSchema.dy_tag.split(',').map(e => {
      const [name, viewCount, id, grounId] = e.split("_")
      return {name, viewCount, id, grounId}
    })
    const tagStr: string = tagList.map(e => `#${e.name}`).join(' ');
    const text_extra = tagList.map(e => `#${e.name}`).map((tag, idx) => {
      let beforeLength = tagList.slice(0, idx).map(e => `#${e.name}`).join(" ").length + (idx > 0 ? 1 : 0)
      return {
        caption_end: beforeLength + tag.length,
        caption_start: beforeLength,
        end: beforeLength + tag.length + (title.length + 1),
        hashtag_id: +tagList[idx].id,
        hashtag_name: tag.substring(1),
        start: beforeLength + (title.length + 1),
        type: 1,
        user_id: '',
      };
    });
    const res = {
      item_title: title,
      caption: tagStr,
      text: `${title} ${tagStr}`,
      text_extra: JSON.stringify(text_extra),
    }
    const encodeRes = {}
    Object.keys(res).forEach(k => {
      encodeRes[k] = encodeURIComponent(res[k])
    })
    return encode ? encodeRes : res;
  }

  publishTask(task: IWonewSer.DyPublishTask) {
    const uri: string = 'https://creator.douyin.com/web/api/media/aweme/create/';

    const params = {
      // "cookie_enabled": "true",
      // "screen_width": "1920",
      // "screen_height": "1080",
      // "browser_language": "zh-CN",
      // "browser_platform": "MacIntel",
      // "browser_name": "Mozilla",
      // "browser_version": "5.0+(Macintosh;+Intel+Mac+OS+X+10_15_7)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/120.0.0.0+Safari/537.36",
      // "browser_online": "true",
      // "timezone_name": "Asia/Shanghai",
      // "aid": "1128",
      // "msToken": "Bpbffw37-Ion74pJDRpXb8VDpU1uJQZ53kv6UHhMoqK3ppu4x0usdcQPyR1fNVvjaVGev8tCJQFTafhO9AZN9fE1FpukGYAgT4QiDCf0GI_NEfy0hH7aoA",
      // "a_bogus": "DJld6c2pMsm1ZjlBxXkz9aDMXlb0YW4qgZENy-pPhtqy",

      // "X-Bogus": "DFSzsdVLwrsTcAP7tijy/5RXoR0u",
      // "_signature": "_02B4Z6wo00001pQRFbgAAIDDejTRRzZcuE6UFREAAMC4kAG0IX-vJgtFbWuhSfCVZb5fyAe1mcRtKh8aCGDWynjIc0Ex7-Ww80.cwryRQcDZ5MQzi6T3tauEQtnhBsVYV6jXomt3GJAiz2Dabc"
    };
    const data = new URLSearchParams({
      'video_id': task.res_uploadVideo.res_uploadVideo_commitUploadInner.Result.Results[0].Vid,
      'ifLongTitle': 'true',
      // 'text': '你哈你好 21312313#23213 #awdwd',
      // 'caption': task.config.tag.split(',').map(t => `#${t}`).join(' '),
      // 'item_title': task.config.title,
      // 'text_extra': '[{"start":13,"end":19,"type":1,"hashtag_name":"23213","hashtag_id":0,"user_id":"","caption_start":8,"caption_end":14},{"start":20,"end":26,"type":1,"hashtag_name":"awdwd","hashtag_id":0,"user_id":"","caption_start":15,"caption_end":21}]',
      'record': 'null',
      'source_info': '{}',
      'activity': '[]',
      'challenges': '[]',
      'mentions': '[]',
      'hashtag_source': '"search/search"',
      'visibility_type': '0',
      'upload_source': '1',
      'is_preview': '0',
      'is_post_assistant': '1',
      'user_declare_info': '{}',
      'hot_sentence': '',
      'knowl_id': '',
      'knowl_order': '0',
      'title_permission': '1',
      'creation_id': IHelper.hash(21) || '7r18qoge1705569261603',
      'poster': task.res_uploadCover.res_uploadCover_commitImageUpload.Result.Results[0].Uri,
      'poster_delay': '0',
      'timing': '0',
      'music_source': '0',
      'music_id': '',
      'download': '1',
      'poster_param': '{}',
      // 'custom_cover_image_height': '504',
      // 'custom_cover_image_width': '672',
      // 'cover_tools_info': '{"cover_width":672,"cover_height":504,"cover_type":"upload","video_cover_source":"upload","is_text_template":0,"is_text":0,"text_num":0,"is_cover_template":0,"tab_name":"","sticker_tab_name":"","filter_tab_name":"","text_content":"","text_template_content":"","is_use_sticker":0,"is_use_filter":0,"text_template_id":"","sticker_id":"","filter_id":[],"recommend_timestamp":"{23600,47200,0}"}',
      'chapter': '{"chapter_details":[],"chapter_type":1}',
      ...this.buildPubTitleConfig(task),
    });
    const headers: RawAxiosRequestHeaders = {
      'Host': 'creator.douyin.com',
      'Cookie': IHelper.covert2StandardCookieStr(task.accountSchema.cookie),
      // 'pragma': 'no-cache',
      // 'cache-control': 'no-cache',
      // 'bd-ticket-guard-version': '2',
      // 'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
      // 'bd-ticket-guard-iteration-version': '1',
      // // 'bd-ticket-guard-ree-public-key': 'BFZM10mBM7DJ2hkH8mCB8X5wm2FJHKaEzArR5Ljlx+rEuoe9b/zAq7kDTf0xCmB1iVB+YfK+bTZt1yP4815fzus=',
      // // 'x-secsdk-csrf-token': '000100000001cef0bc6d28f2614ca76e7ec6a2825d3f471f27972ec0d6ee5c291e2703dfe29217ab66329c8c42da',
      // 'sec-ch-ua-mobile': '?0',
      // 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      // 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
      // 'accept': 'application/json, text/plain, */*',
      // 'bd-ticket-guard-web-version': '1',
      // // 'bd-ticket-guard-client-data': 'eyJ0c19zaWduIjoidHMuMS40MzM1MTkwYzRjN2ExYzUwZTk0NGYzNWJlNTc4NzZhNjA0YTdkYzRlZTk1NjBmMzk4YWE2NjRhYWVkNWE1NTY2YzRmYmU4N2QyMzE5Y2YwNTMxODYyNGNlZGExNDkxMWNhNDA2ZGVkYmViZWRkYjJlMzBmY2U4ZDRmYTAyNTc1ZCIsInJlcV9jb250ZW50IjoidGlja2V0LHBhdGgsdGltZXN0YW1wIiwicmVxX3NpZ24iOiJNRVFDSUN6NkFYUUJqMHN5b2ZweEJXcWVVUUh0VkRXWjNVSE4xWlFXZUhjbmNJQmpBaUI1cU11TlRhOUJiTmJ6RGJyWXdLYXpDcUd4cWhSem9nU01BakYzdkx1bTRnPT0iLCJ0aW1lc3RhbXAiOjE3MDU1NzAzOTB9',
      // 'sec-ch-ua-platform': '"macOS"',
      // 'origin': 'https://creator.douyin.com',
      // 'sec-fetch-site': 'same-origin',
      // 'sec-fetch-mode': 'cors',
      // 'sec-fetch-dest': 'empty',
      // 'referer': 'https://creator.douyin.com/creator-micro/content/publish?enter_from=publish_page',
      // 'accept-language': 'zh-CN,zh;q=0.9',
    };
    return defer(() =>
      axios.post(uri, data, { params, headers }),
    ).pipe(
      map(res => {
        console.log("Publish video", res.data)
        if (res.data?.status_code !== 0 || !res.data?.aweme?.aweme_id) {
          ILogger.info(`Publish video failed.: ${JSON.stringify(res.data)}`)
          throw new HttpException(`Publish video failed.`, HttpStatus.BAD_REQUEST)
        }
        task.res_publishVideo = res.data
        return task
      }),
    );
  }

  async getTotalPosts(cookie: string): Promise<{items: IWonewSer.AccountPost[], total: number}> {
    let max_cursor: string = "", list: IWonewSer.AccountPost[] = []
    while(true) {
      const { items, total } = await lastValueFrom(this.getCursorPosts(cookie, max_cursor))
      list = [...list, ...items]
      max_cursor = [...items].pop().publish_timestamp.toString()
      if (list.length >= total) break
    }
    return {items: list, total: list.length}
  }

  getCursorPosts(cookie: string, cursor?: string): Observable<{items: IWonewSer.AccountPost[], total: number}> {
    const params = {
      "scene": "star_atlas",
      "device_platform": "webapp",
      "status": "0",
      "count": "50",  // max 20
      "max_cursor": cursor,
    }
    const headers: RawAxiosRequestHeaders = {
      'authority': 'creator.douyin.com',
      'accept': 'application/json, text/plain, */*',
      'accept-language': 'zh-CN,zh;q=0.9',
      'cache-control': 'no-cache',
      'cookie': IHelper.covert2StandardCookieStr(cookie),
      'pragma': 'no-cache',
      'referer': 'https://creator.douyin.com/creator-micro/content/manage',
      'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
      'sec-ch-ua-mobile': '?0',
      'sec-ch-ua-platform': '"macOS"',
      'sec-fetch-dest': 'empty',
      'sec-fetch-mode': 'cors',
      'sec-fetch-site': 'same-origin',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    }
    
    return defer(() =>
      axios.get('https://creator.douyin.com/web/api/media/aweme/post', {
        headers, params
      })
    ).pipe(
      map(d => {
        if (d.data?.status_code !== 0) {
          throw new HttpException("Get posts failed.", HttpStatus.BAD_REQUEST)
        }
        return {items: d.data.aweme_list.map(this.formatPost), total: d.data.total}
      })
    )
  }

  getPosts(cookie: string, opt?: IWonewSer.PaginationPrams & {max_cursor?: string}) {
    return this.getCursorPosts(cookie, opt?.max_cursor).pipe(
      map(res => {
        return {
          list: res.items,
          total: res.total,
          page: +(opt.page || 1),
          pageSize: +(opt.pageSize || 20),
        }
      })
    )
    // return defer(() => this.getTotalPosts(cookie)).pipe(
    //   map(({items, total}) => {
    //     const pn = +(opt.page || 1)
    //     const ps = +(opt.pageSize || 20)
    //     return {
    //       list: items.slice((pn - 1) * ps, pn * ps),
    //       total,
    //       page: pn,
    //       pageSize: ps,
    //     }
    //   })
    // )
  }

  formatPost(post: any): IWonewSer.AccountPost {
    return {
      id: post.aweme_id,
      title: post.item_title,
      cover: post.Cover?.url_list?.[0],
      url: post?.video?.download_addr?.url_list?.[0],
      publish_date: moment(post.create_time * 1000).format("YYYY-MM-DD HH:mm:ss"),
      publish_timestamp: post.create_time * 1000,
      view_count: post.statistics.play_count, // 播放
      like_count: post.statistics.digg_count, // 点赞
      coin_count: 0, // 投币
      fav_count: post.statistics.collect_count, // 收藏
      share_count: post.statistics.share_count, // 分享
      danmaku_count: 0, // 弹幕
      reply_count: post.statistics.comment_count, // 分享
    }
  }

  getUid(task: IWonewSer.DyPublishTask): string {
    return task.platformUser.uid
  }

  getTaskUploadAuth(task: IWonewSer.DyPublishTask): IWonewSer.DyUploadAuth {
    return JSON.parse(task.res_requestAuth.auth) as IWonewSer.DyUploadAuth;
  }

  parseUploadNode(res: any): IWonewSer.DyUploadRequestNode {
    const node = res.Result.InnerUploadAddress.UploadNodes[0];
    return {
      'Vid': node.Vid,
      'StoreUri': node.StoreInfos[0].StoreUri,
      'Auth': node.StoreInfos[0].Auth,
      'UploadID': node.StoreInfos[0].UploadID,
      'UploadHeader': node.StoreInfos[0].UploadHeader,
      'StorageHeader': node.StoreInfos[0].StorageHeader,
      'UploadHost': node.UploadHost,
      'SessionKey': node.SessionKey,
      'AdvanceOption': res.Result.InnerUploadAddress.AdvanceOption,
      'UploadUri': `https://${node.UploadHost}/upload/v1/${node.StoreInfos[0].StoreUri}`,
    };
  }

  suggestTag(keyword: string) {
    const params = {
      "source": "challenge_create",
      "aid": "2906",
      "keyword": keyword,
      "cookie_enabled": "true",
      "screen_width": "1920",
      "screen_height": "1080",
      "browser_language": "zh-CN",
      "browser_platform": "MacIntel",
      "browser_name": "Mozilla",
      "browser_version": "5.0+(Macintosh;+Intel+Mac+OS+X+10_15_7)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/120.0.0.0+Safari/537.36",
      "browser_online": "true",
      "timezone_name": "Asia/Shanghai",
      // "msToken": "M5u8Oxx3zIyRwq3AO8fKi7AGUbpDUmurm5Nln4kUHvI_UFSeNY4AqlwbflT3px5wO4tVCPe1AJy66yMb57FO6YpO4jiu3yyKisiBt702-4srKVcaEe6zVA",
      // "X-Bogus": "DFSzsdVLtKxANCP7tEfM5QRXoR0M",
      // "_signature": "_02B4Z6wo00001D1tw1QAAIDB00gHqtGxb6A9acfAAGryDFLCFW7le4wm9G9lVimaCzMNFCyPx.sB0wv-2s.uh0ayZ6hw3UnJuxU39D.l91HcJrxV0.V0c5.COkPq33wM8h-H4hvkCdmRl5fj40"
    }
    return defer(() => 
      axios.get("https://creator.douyin.com/aweme/v1/search/challengesug/", {params})
    ).pipe(
      map(d => IResponse.success(d.data?.sug_list || []))
    )
  }

  sendSmsCode(cookie: string) {
    // return IHelper.parseQueryStr(`ttwid=&aid=10006&type=22&timestamp=1706870254916&msToken=6Ji8lkQYMANJqDsPoOJkJ8YFfxHU6X9V2vF5nVLQ3wVIMEUirgtDxXDSo3aW_sw59AKaW8ld0fhh734yqwhCi1NxjjkB7_62xV_Kq7YkhTzfl_5aVGWZ9A==&X-Bogus=DFSzsdVLitsANCP7tEEkE5RXoR/K&_signature=_02B4Z6wo00001ZIUodAAAIDAfDFlLDptjqGSEKVAAAE6hv0sJXXJrDSGLA8gGX43-hMBU9Reeg2VD57CbtIT6rCRVmiBNxkthaRr-PHrjbw9qpO5fUfQ7vdqhkbB0o7eoxkkzbjJXCuDqIin4e`)
    const params = {
      "ttwid": "",
      "aid": "10006",
      "type": "22",
      "timestamp": Date.now().toString(),
      // "msToken": "6Ji8lkQYMANJqDsPoOJkJ8YFfxHU6X9V2vF5nVLQ3wVIMEUirgtDxXDSo3aW_sw59AKaW8ld0fhh734yqwhCi1NxjjkB7_62xV_Kq7YkhTzfl_5aVGWZ9A",
      // "X-Bogus": "DFSzsdVLitsANCP7tEEkE5RXoR/K",
      // "_signature": "_02B4Z6wo00001ZIUodAAAIDAfDFlLDptjqGSEKVAAAE6hv0sJXXJrDSGLA8gGX43-hMBU9Reeg2VD57CbtIT6rCRVmiBNxkthaRr-PHrjbw9qpO5fUfQ7vdqhkbB0o7eoxkkzbjJXCuDqIin4e"
    }
    const headers: RawAxiosRequestHeaders = {
      'authority': 'creator.douyin.com',
      'cookie': cookie,
      'content-type': 'application/x-www-form-urlencoded',
      'accept': 'text/javascript, text/html, application/xml, text/xml, */*',
      'accept-language': 'zh-CN,zh;q=0.9',
      'cache-control': 'no-cache',
      'pragma': 'no-cache',
      'referer': 'https://creator.douyin.com/creator-micro/content/publish?enter_from=publish_page',
    }
    return defer(() => 
      axios.get('https://creator.douyin.com/passport/web/send_code/', {headers, params})
    ).pipe(
      map(res => {
        let mock = {
          "data": {
              "mobile": "171******04",
              "mobile_ticket": "",
              "retry_time": 60
          },
          "message": "success"
        }
        if (res.data?.message !== "success") {
          ILogger.info(`sendSmsCode failed. ${JSON.stringify(res.data)}`)
          throw new HttpException(res.data?.data?.description, HttpStatus.BAD_REQUEST)
        }
        return IResponse.success(res.data)
      })
    )
  }

  validateSmsCode(cookie: string, code: string) {
    const params = {
      "ttwid": "",
      "aid": "10006",
      "code": code,
      "type": "22",
      "timestamp": Date.now().toString(),
      // "msToken": "6Ji8lkQYMANJqDsPoOJkJ8YFfxHU6X9V2vF5nVLQ3wVIMEUirgtDxXDSo3aW_sw59AKaW8ld0fhh734yqwhCi1NxjjkB7_62xV_Kq7YkhTzfl_5aVGWZ9A",
      // "X-Bogus": "DFSzsdVLLr0ANCP7tEEd55RXoR/I",
      // "_signature": "_02B4Z6wo00001mebz3wAAIDDib4Lgz-A7KZnn8vAAPxphv0sJXXJrDSGLA8gGX43-hMBU9Reeg2VD57CbtIT6rCRVmiBNxkthaRr-PHrjbw9qpO5fUfQ7vdqhkbB0o7eoxkkzbjJXCuDqIinea"
    }
    const headers: RawAxiosRequestHeaders = {
      'authority': 'creator.douyin.com',
      'accept': 'text/javascript, text/html, application/xml, text/xml, */*',
      'accept-language': 'zh-CN,zh;q=0.9',
      'cache-control': 'no-cache',
      'content-type': 'application/x-www-form-urlencoded',
      'cookie': cookie,
      'pragma': 'no-cache',
      'referer': 'https://creator.douyin.com/creator-micro/content/publish?enter_from=publish_page',
      'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
      'sec-ch-ua-mobile': '?0',
      'sec-ch-ua-platform': '"macOS"',
      'sec-fetch-dest': 'empty',
      'sec-fetch-mode': 'cors',
      'sec-fetch-site': 'same-origin',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      // 'x-secsdk-csrf-token': '0001000000017492b267ecba1e9d3709930d282976bb1d4fc6c0c86fce0b33437c4c7c510fe717b0052241d89370',
      // 'x-tt-passport-csrf-token': '8ac577ac5cad0f1a486aaad9e00cb304'
    }
    return defer(() => 
      axios.get('https://creator.douyin.com/passport/web/validate_code/', {
        headers, params
      })
    ).pipe(
      map(res => {
        let mock = {"data":{"ticket":"VTIDEFKC322ND7HFJA2FDJ3CFMK4BGQ67ERZR6"},"message":"success"}
        if (res.data?.message !== "success") {
          ILogger.info(`validateSmsCode failed. ${JSON.stringify(res.data)}`)
          throw new HttpException(res.data?.data?.description, HttpStatus.BAD_REQUEST)
        }
        return IResponse.success(res.data)
      })
    )
  }

}